home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacScale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  16.1 KB  |  604 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkMacScale.c --
  3.  *
  4.  *    This file implements the Macintosh specific portion of the 
  5.  *    scale widget.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkMacScale.c 1.3 96/10/17 13:16:18
  13.  */
  14.  
  15. #include "tkScale.h"
  16. #include "tkInt.h"
  17. #include <Controls.h>
  18. #include "tkMacInt.h"
  19.  
  20. /*
  21.  * Defines used in this file.
  22.  */
  23. #define slider        1110
  24. #define inSlider    1
  25. #define inInc        2
  26. #define inDecr        3
  27.  
  28. /*
  29.  * Declaration of Macintosh specific scale structure.
  30.  */
  31.  
  32. typedef struct MacScale {
  33.     TkScale info;        /* Generic scale info. */
  34.     int flags;            /* Flags. */
  35.     ControlRef scaleHandle;    /* Handle to the Scale control struct. */
  36. } MacScale;
  37.  
  38. /*
  39.  * Globals uses locally in this file.
  40.  */
  41. static ControlActionUPP scaleActionProc = NULL; /* Pointer to func. */
  42.  
  43. /*
  44.  * Forward declarations for procedures defined later in this file:
  45.  */
  46.  
  47. static void        MacScaleEventProc _ANSI_ARGS_((ClientData clientData,
  48.                 XEvent *eventPtr));
  49. static pascal void    ScaleActionProc _ANSI_ARGS_((ControlRef theControl,
  50.                 ControlPartCode partCode));
  51.  
  52. /*
  53.  *----------------------------------------------------------------------
  54.  *
  55.  * TkpCreateScale --
  56.  *
  57.  *    Allocate a new TkScale structure.
  58.  *
  59.  * Results:
  60.  *    Returns a newly allocated TkScale structure.
  61.  *
  62.  * Side effects:
  63.  *    None.
  64.  *
  65.  *----------------------------------------------------------------------
  66.  */
  67.  
  68. TkScale *
  69. TkpCreateScale(tkwin)
  70.     Tk_Window tkwin;
  71. {
  72.     MacScale *macScalePtr;;
  73.     
  74.     macScalePtr = (MacScale *) ckalloc(sizeof(MacScale));
  75.     macScalePtr->scaleHandle = NULL;
  76.     if (scaleActionProc == NULL) {
  77.     scaleActionProc = NewControlActionProc(ScaleActionProc);
  78.     }
  79.     
  80.     Tk_CreateEventHandler(tkwin, ButtonPressMask,
  81.         MacScaleEventProc, (ClientData) macScalePtr);
  82.         
  83.     return (TkScale *) macScalePtr;
  84. }
  85.  
  86. /*
  87.  *----------------------------------------------------------------------
  88.  *
  89.  * TkpDestroyScale --
  90.  *
  91.  *    Free Macintosh specific resources.
  92.  *
  93.  * Results:
  94.  *    None
  95.  *
  96.  * Side effects:
  97.  *    The slider control is destroyed.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101.  
  102. void
  103. TkpDestroyScale(scalePtr)
  104.     TkScale *scalePtr;
  105. {
  106.     MacScale *macScalePtr = (MacScale *) scalePtr;
  107.     
  108.     /*
  109.      * Free Macintosh control.
  110.      */
  111.     if (macScalePtr->scaleHandle != NULL) {
  112.         DisposeControl(macScalePtr->scaleHandle);
  113.     }
  114. }
  115.  
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *
  119.  * TkpDisplayScale --
  120.  *
  121.  *    This procedure is invoked as an idle handler to redisplay
  122.  *    the contents of a scale widget.
  123.  *
  124.  * Results:
  125.  *    None.
  126.  *
  127.  * Side effects:
  128.  *    The scale gets redisplayed.
  129.  *
  130.  *----------------------------------------------------------------------
  131.  */
  132.  
  133. void
  134. TkpDisplayScale(clientData)
  135.     ClientData clientData;    /* Widget record for scale. */
  136. {
  137.     TkScale *scalePtr = (TkScale *) clientData;
  138.     Tk_Window tkwin = scalePtr->tkwin;
  139.     Tcl_Interp *interp = scalePtr->interp;
  140.     int result;
  141.     char string[PRINT_CHARS];
  142.     MacScale *macScalePtr = (MacScale *) clientData;
  143.     Rect r;
  144.     WindowRef windowRef;
  145.     GWorldPtr destPort;        
  146.     CGrafPtr saveWorld;
  147.     GDHandle saveDevice;
  148.     MacDrawable *macDraw;
  149.     
  150.     if ((scalePtr->tkwin == NULL) || !Tk_IsMapped(scalePtr->tkwin)) {
  151.     goto done;
  152.     }
  153.  
  154.     /*
  155.      * Invoke the scale's command if needed.
  156.      */
  157.  
  158.     Tcl_Preserve((ClientData) scalePtr);
  159.     if ((scalePtr->flags & INVOKE_COMMAND) && (scalePtr->command != NULL)) {
  160.     Tcl_Preserve((ClientData) interp);
  161.     sprintf(string, scalePtr->format, scalePtr->value);
  162.     result = Tcl_VarEval(interp, scalePtr->command,    " ", string,
  163.                              (char *) NULL);
  164.     if (result != TCL_OK) {
  165.         Tcl_AddErrorInfo(interp, "\n    (command executed by scale)");
  166.         Tcl_BackgroundError(interp);
  167.     }
  168.     Tcl_Release((ClientData) interp);
  169.     }
  170.     scalePtr->flags &= ~INVOKE_COMMAND;
  171.     if (scalePtr->tkwin == NULL) {
  172.     Tcl_Release((ClientData) scalePtr);
  173.     return;
  174.     }
  175.     Tcl_Release((ClientData) scalePtr);
  176.  
  177.     /*
  178.      * Now handle the part of redisplay that is the same for
  179.      * horizontal and vertical scales:  border and traversal
  180.      * highlight.
  181.      */
  182.  
  183.     if (scalePtr->highlightWidth != 0) {
  184.     GC gc;
  185.     
  186.     if (scalePtr->flags & GOT_FOCUS) {
  187.         gc = Tk_GCForColor(scalePtr->highlightColorPtr, Tk_WindowId(tkwin));
  188.     } else {
  189.         gc = Tk_GCForColor(scalePtr->highlightBgColorPtr, Tk_WindowId(tkwin));
  190.     }
  191.     Tk_DrawFocusHighlight(tkwin, gc, scalePtr->highlightWidth, Tk_WindowId(tkwin));
  192.     }
  193.     Tk_Draw3DRectangle(tkwin, Tk_WindowId(tkwin), scalePtr->bgBorder,
  194.         scalePtr->highlightWidth, scalePtr->highlightWidth,
  195.         Tk_Width(tkwin) - 2*scalePtr->highlightWidth,
  196.         Tk_Height(tkwin) - 2*scalePtr->highlightWidth,
  197.         scalePtr->borderWidth, scalePtr->relief);
  198.  
  199.     /*
  200.      * Set up port for drawing Macintosh control.
  201.      */
  202.     macDraw = (MacDrawable *) Tk_WindowId(tkwin);
  203.     destPort = TkMacGetDrawablePort(Tk_WindowId(tkwin));
  204.     GetGWorld(&saveWorld, &saveDevice);
  205.     SetGWorld(destPort, NULL);
  206.     TkMacSetUpClippingRgn(Tk_WindowId(tkwin));
  207.  
  208.     /*
  209.      * Create Macintosh control.
  210.      */
  211.     if (macScalePtr->scaleHandle == NULL) {
  212.         r.left = r.top = 0;
  213.         r.right = r.bottom = 1;
  214.         /* TODO: initial value. */
  215.         /* 16*slider+4 */
  216.     macScalePtr->scaleHandle = NewControl((WindowRef) destPort, 
  217.         &r, "\p", false, (short) 35, 0, 1000,
  218.         16*slider, (SInt32) macScalePtr);
  219.  
  220.     /*
  221.      * If we are foremost than make us active.
  222.      */
  223.     if ((WindowPtr) destPort == FrontWindow()) {
  224.         macScalePtr->flags |= ACTIVE;
  225.     }
  226.     }
  227.     windowRef  = (**macScalePtr->scaleHandle).contrlOwner;
  228.  
  229.     /*
  230.      * We can't use the Macintosh commands SizeControl and MoveControl as these
  231.      * calls will also cause a redraw which in our case will also cause
  232.      * flicker.  To avoid this we adjust the control record directly.  The
  233.      * Draw1Control command appears to just draw where ever the control says to
  234.      * draw so this seems right.
  235.      *
  236.      * NOTE: changing the control record directly may not work when
  237.      * Apple releases the Copland version of the MacOS in late 1996.
  238.      */
  239.      
  240.     (**macScalePtr->scaleHandle).contrlRect.left = macDraw->xOff + scalePtr->inset;
  241.     (**macScalePtr->scaleHandle).contrlRect.top = macDraw->yOff + scalePtr->inset;
  242.     (**macScalePtr->scaleHandle).contrlRect.right = macDraw->xOff + Tk_Width(tkwin)
  243.     - scalePtr->inset;
  244.     (**macScalePtr->scaleHandle).contrlRect.bottom = macDraw->yOff +
  245.     Tk_Height(tkwin) - scalePtr->inset;
  246.  
  247.     /*
  248.      * Set the thumb and resolution etc.
  249.      */
  250.     (**macScalePtr->scaleHandle).contrlMin = (SInt16) scalePtr->toValue;
  251.     (**macScalePtr->scaleHandle).contrlMax = (SInt16) scalePtr->fromValue;
  252.     (**macScalePtr->scaleHandle).contrlValue = (SInt16) scalePtr->value;
  253.  
  254.     /*
  255.      * Finally draw the control.
  256.      */
  257.     (**macScalePtr->scaleHandle).contrlVis = 255;
  258.     (**macScalePtr->scaleHandle).contrlHilite = 0;
  259.     Draw1Control(macScalePtr->scaleHandle);
  260.  
  261.     SetGWorld(saveWorld, saveDevice);
  262.  
  263.     done:
  264.     scalePtr->flags &= ~REDRAW_ALL;
  265. }
  266.  
  267. /*
  268.  *----------------------------------------------------------------------
  269.  *
  270.  * TkpScaleElement --
  271.  *
  272.  *    Determine which part of a scale widget lies under a given
  273.  *    point.
  274.  *
  275.  * Results:
  276.  *    The return value is either TROUGH1, SLIDER, TROUGH2, or
  277.  *    OTHER, depending on which of the scale's active elements
  278.  *    (if any) is under the point at (x,y).
  279.  *
  280.  * Side effects:
  281.  *    None.
  282.  *
  283.  *----------------------------------------------------------------------
  284.  */
  285.  
  286. int
  287. TkpScaleElement(scalePtr, x, y)
  288.     TkScale *scalePtr;        /* Widget record for scale. */
  289.     int x, y;            /* Coordinates within scalePtr's window. */
  290. {
  291.     MacScale *macScalePtr = (MacScale *) scalePtr;
  292.     ControlPartCode part;
  293.     Point where;
  294.     Rect bounds;
  295.     CGrafPtr saveWorld;
  296.     GDHandle saveDevice;
  297.     GWorldPtr destPort;        
  298.  
  299.     destPort = TkMacGetDrawablePort(Tk_WindowId(scalePtr->tkwin));
  300.     GetGWorld(&saveWorld, &saveDevice);
  301.     SetGWorld(destPort, NULL);
  302.  
  303.     /*
  304.      * All of the calculations in this procedure mirror those in
  305.      * DisplayScrollbar.  Be sure to keep the two consistent.
  306.      */
  307.  
  308.     TkMacWinBounds((TkWindow *) scalePtr->tkwin, &bounds);        
  309.     where.h = x + bounds.left;
  310.     where.v = y + bounds.top;
  311.     part = TestControl(macScalePtr->scaleHandle, where);
  312.     
  313.     SetGWorld(saveWorld, saveDevice);
  314.     
  315.     switch (part) {
  316.         case inSlider:
  317.         return SLIDER;
  318.         case inInc:
  319.         if (scalePtr->vertical) {
  320.         return TROUGH1;
  321.         } else {
  322.         return TROUGH2;
  323.         }
  324.         case inDecr:
  325.         if (scalePtr->vertical) {
  326.         return TROUGH2;
  327.         } else {
  328.         return TROUGH1;
  329.         }
  330.         default:
  331.         return OTHER;
  332.     }
  333. }
  334.  
  335. /*
  336.  *--------------------------------------------------------------
  337.  *
  338.  * TkpSetScaleValue --
  339.  *
  340.  *    This procedure changes the value of a scale and invokes
  341.  *    a Tcl command to reflect the current position of a scale
  342.  *
  343.  * Results:
  344.  *    None.
  345.  *
  346.  * Side effects:
  347.  *    A Tcl command is invoked, and an additional error-processing
  348.  *    command may also be invoked.  The scale's slider is redrawn.
  349.  *
  350.  *--------------------------------------------------------------
  351.  */
  352.  
  353. void
  354. TkpSetScaleValue(scalePtr, value, setVar, invokeCommand)
  355.     register TkScale *scalePtr;    /* Info about widget. */
  356.     double value;        /* New value for scale.  Gets adjusted
  357.                  * if it's off the scale. */
  358.     int setVar;            /* Non-zero means reflect new value through
  359.                  * to associated variable, if any. */
  360.     int invokeCommand;        /* Non-zero means invoked -command option
  361.                  * to notify of new value, 0 means don't. */
  362. {
  363.     char string[PRINT_CHARS];
  364.  
  365.     value = TkRoundToResolution(scalePtr, value);
  366.     if ((value < scalePtr->fromValue)
  367.         ^ (scalePtr->toValue < scalePtr->fromValue)) {
  368.     value = scalePtr->fromValue;
  369.     }
  370.     if ((value > scalePtr->toValue)
  371.         ^ (scalePtr->toValue < scalePtr->fromValue)) {
  372.     value = scalePtr->toValue;
  373.     }
  374.     if (scalePtr->flags & NEVER_SET) {
  375.     scalePtr->flags &= ~NEVER_SET;
  376.     } else if (scalePtr->value == value) {
  377.     return;
  378.     }
  379.     scalePtr->value = value;
  380.     if (invokeCommand) {
  381.     scalePtr->flags |= INVOKE_COMMAND;
  382.     }
  383.     TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER);
  384.  
  385.     if (setVar && (scalePtr->varName != NULL)) {
  386.     sprintf(string, scalePtr->format, scalePtr->value);
  387.     scalePtr->flags |= SETTING_VAR;
  388.     Tcl_SetVar(scalePtr->interp, scalePtr->varName, string,
  389.            TCL_GLOBAL_ONLY);
  390.     scalePtr->flags &= ~SETTING_VAR;
  391.     }
  392. }
  393.  
  394. /*
  395.  *----------------------------------------------------------------------
  396.  *
  397.  * TkpPixelToValue --
  398.  *
  399.  *    Given a pixel within a scale window, return the scale
  400.  *    reading corresponding to that pixel.
  401.  *
  402.  * Results:
  403.  *    A double-precision scale reading.  If the value is outside
  404.  *    the legal range for the scale then it's rounded to the nearest
  405.  *    end of the scale.
  406.  *
  407.  * Side effects:
  408.  *    None.
  409.  *
  410.  *----------------------------------------------------------------------
  411.  */
  412.  
  413. double
  414. TkpPixelToValue(scalePtr, x, y)
  415.     register TkScale *scalePtr;        /* Information about widget. */
  416.     int x, y;                /* Coordinates of point within
  417.                      * window. */
  418. {
  419.     double value, pixelRange;
  420.  
  421.     if (scalePtr->vertical) {
  422.     pixelRange = Tk_Height(scalePtr->tkwin) - scalePtr->sliderLength
  423.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  424.     value = y;
  425.     } else {
  426.     pixelRange = Tk_Width(scalePtr->tkwin) - scalePtr->sliderLength
  427.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  428.     value = x;
  429.     }
  430.  
  431.     if (pixelRange <= 0) {
  432.     /*
  433.      * Not enough room for the slider to actually slide:  just return
  434.      * the scale's current value.
  435.      */
  436.  
  437.     return scalePtr->value;
  438.     }
  439.     value -= scalePtr->sliderLength/2 + scalePtr->inset
  440.         + scalePtr->borderWidth;
  441.     value /= pixelRange;
  442.     if (value < 0) {
  443.     value = 0;
  444.     }
  445.     if (value > 1) {
  446.     value = 1;
  447.     }
  448.     value = scalePtr->fromValue +
  449.         value * (scalePtr->toValue - scalePtr->fromValue);
  450.     return TkRoundToResolution(scalePtr, value);
  451. }
  452.  
  453. /*
  454.  *----------------------------------------------------------------------
  455.  *
  456.  * TkpValueToPixel --
  457.  *
  458.  *    Given a reading of the scale, return the x-coordinate or
  459.  *    y-coordinate corresponding to that reading, depending on
  460.  *    whether the scale is vertical or horizontal, respectively.
  461.  *
  462.  * Results:
  463.  *    An integer value giving the pixel location corresponding
  464.  *    to reading.  The value is restricted to lie within the
  465.  *    defined range for the scale.
  466.  *
  467.  * Side effects:
  468.  *    None.
  469.  *
  470.  *----------------------------------------------------------------------
  471.  */
  472.  
  473. int
  474. TkpValueToPixel(scalePtr, value)
  475.     register TkScale *scalePtr;        /* Information about widget. */
  476.     double value;            /* Reading of the widget. */
  477. {
  478.     int y, pixelRange;
  479.     double valueRange;
  480.  
  481.     valueRange = scalePtr->toValue - scalePtr->fromValue;
  482.     pixelRange = (scalePtr->vertical ? Tk_Height(scalePtr->tkwin)
  483.         : Tk_Width(scalePtr->tkwin)) - scalePtr->sliderLength
  484.         - 2*scalePtr->inset - 2*scalePtr->borderWidth;
  485.     if (valueRange == 0) {
  486.     y = 0;
  487.     } else {
  488.     y = (int) ((value - scalePtr->fromValue) * pixelRange
  489.           / valueRange + 0.5);
  490.     if (y < 0) {
  491.         y = 0;
  492.     } else if (y > pixelRange) {
  493.         y = pixelRange;
  494.     }
  495.     }
  496.     y += scalePtr->sliderLength/2 + scalePtr->inset + scalePtr->borderWidth;
  497.     return y;
  498. }
  499.  
  500. /*
  501.  *--------------------------------------------------------------
  502.  *
  503.  * MacScaleEventProc --
  504.  *
  505.  *    This procedure is invoked by the Tk dispatcher for 
  506.  *    ButtonPress events on scales.
  507.  *
  508.  * Results:
  509.  *    None.
  510.  *
  511.  * Side effects:
  512.  *    When the window gets deleted, internal structures get
  513.  *    cleaned up.  When it gets exposed, it is redisplayed.
  514.  *
  515.  *--------------------------------------------------------------
  516.  */
  517.  
  518. static void
  519. MacScaleEventProc(clientData, eventPtr)
  520.     ClientData clientData;    /* Information about window. */
  521.     XEvent *eventPtr;        /* Information about event. */
  522. {
  523.     MacScale *macScalePtr = (MacScale *) clientData;
  524.     Point where;
  525.     Rect bounds;
  526.     int part, x, y, dummy;
  527.     unsigned int state;
  528.     CGrafPtr saveWorld;
  529.     GDHandle saveDevice;
  530.     GWorldPtr destPort;
  531.     Window dummyWin;
  532.  
  533.     /*
  534.      * To call Macintosh control routines we must have the port
  535.      * set to the window containing the control.  We will then test
  536.      * which part of the control was hit and act accordingly.
  537.      */
  538.     destPort = TkMacGetDrawablePort(Tk_WindowId(macScalePtr->info.tkwin));
  539.     GetGWorld(&saveWorld, &saveDevice);
  540.     SetGWorld(destPort, NULL);
  541.     TkMacSetUpClippingRgn(Tk_WindowId(macScalePtr->info.tkwin));
  542.  
  543.     TkMacWinBounds((TkWindow *) macScalePtr->info.tkwin, &bounds);        
  544.     where.h = eventPtr->xbutton.x + bounds.left;
  545.     where.v = eventPtr->xbutton.y + bounds.top;
  546.     part = TestControl(macScalePtr->scaleHandle, where);
  547.     if (part == 0) {
  548.     return;
  549.     }
  550.     
  551.     part = TrackControl(macScalePtr->scaleHandle, where, scaleActionProc);
  552.     
  553.     /*
  554.      * Update the value for the widget.
  555.      */
  556.     macScalePtr->info.value = (**macScalePtr->scaleHandle).contrlValue;
  557.     /* TkpSetScaleValue(&macScalePtr->info, macScalePtr->info.value, 1, 0); */
  558.  
  559.     /*
  560.      * The TrackControl call will "eat" the ButtonUp event.  We now
  561.      * generate a ButtonUp event so Tk will unset implicit grabs etc.
  562.      */
  563.     GetMouse(&where);
  564.     XQueryPointer(NULL, None, &dummyWin, &dummyWin, &x,
  565.     &y, &dummy, &dummy, &state);
  566.     TkGenerateButtonEvent(x, y, Tk_WindowId(macScalePtr->info.tkwin), state);
  567.  
  568.     SetGWorld(saveWorld, saveDevice);
  569. }
  570.  
  571. /*
  572.  *--------------------------------------------------------------
  573.  *
  574.  * ScaleActionProc --
  575.  *
  576.  *    Callback procedure used by the Macintosh toolbox call
  577.  *    TrackControl.  This call will update the display while
  578.  *    the scrollbar is being manipulated by the user.
  579.  *
  580.  * Results:
  581.  *    None.
  582.  *
  583.  * Side effects:
  584.  *    May change the display.
  585.  *
  586.  *--------------------------------------------------------------
  587.  */
  588.  
  589. static pascal void
  590. ScaleActionProc(ControlRef theControl, ControlPartCode partCode)
  591.     /* ControlRef theControl;    /* Handle to scrollbat control */
  592.     /* ControlPartCode partCode;    /* Part of scrollbar that was "hit" */
  593. {
  594.     register int value;
  595.     register TkScale *scalePtr = (TkScale *) GetCRefCon(theControl);
  596.  
  597.     value = (**theControl).contrlValue;
  598.     TkpSetScaleValue(scalePtr, value, 1, 1);
  599.     Tcl_Preserve((ClientData) scalePtr);
  600.     Tcl_DoOneEvent(TCL_IDLE_EVENTS);
  601.     Tcl_Release((ClientData) scalePtr);
  602. }
  603.  
  604.